/** Copyright (c) 2012, peter.ducai@gmail.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the Peter "daemonna" Ducai nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL PETER "daemonna" DUCAI BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package thesigner.commons;

/**
 *
 * @author peter.ducai@gmail.com
 */
public final class microCLI {

    /**
     * type of switch/option, each can be configured as short option (without
     * value)
     */
    public enum OPTION_TYPE {

        POSIX, //option with '-' like -zxvf
        GNU, // option with '--' like --max-depth 1  OR --max-depth=1
        JAVA, //option '-D' like -Djava.awt.headless=true
        SIMPLE //option '-' like -headless=true
    };
    private String[] options = new String[100]; //option without '-' sign
    private String[] values = new String[100]; //value of option
    private String[] descriptions = new String[100];
    private String[] arguments = new String[100];
    boolean[] requireds = new boolean[100]; //if required, option MUST be found on command line
    boolean[] option_onlys = new boolean[100]; //if true, option doesn't contain value
    boolean[] selecteds = new boolean[100]; //found on command line
    int option_count = 0; //number of options, index of last element
    OPTION_TYPE type;
    String opt_switch = "-"; //simple switch by default
    boolean foundmissingwrong = false;
    String version = "0.1";

    /**
     * constructor with type "simple"
     */
    public microCLI() {        
        SetType("SIMPLE"); //simple by default
        option_count = 0;
        SetOption("h", "list all options", false, false); //allways add -h option at beginning
    }
    
    public void printBanner(){
        System.out.println();
        System.out.println("microCLI Java edition "+version);
        System.out.println("Copyright (c) 2012, peter.ducai@gmail.com All rights reserved.");
        System.out.println("Processing command line parameters...:");
    }

    /**
     * set type of switch, see enum for explanation
     *
     * @param t type of switch
     */
    public void SetType(String t) {

        switch (t) {
            case "SIMPLE":
                type = OPTION_TYPE.SIMPLE;
                opt_switch = "-";
                break;
            case "POSIX":
                type = OPTION_TYPE.POSIX;
                opt_switch = "-";
                break;
            case "GNU":
                type = OPTION_TYPE.GNU;
                opt_switch = "--";
                break;
            case "JAVA":
                type = OPTION_TYPE.JAVA;
                opt_switch = "-D";
                break;
        }
    }

    /**
     * set switch/option
     *
     * @param opt
     * @param des
     * @param req
     * @param optonly
     */
    public void SetOption(String opt, String des, boolean req, boolean optonly) {
        opt = opt_switch + opt; //put selected switch in front of option, for example 'g' -> '-g'
        options[option_count] = opt;
        values[option_count] = "";
        descriptions[option_count] = des;
        requireds[option_count] = req;
        option_onlys[option_count] = optonly;
        selecteds[option_count] = false; //not selected by default

        //increment count
        option_count++;
    }

    /**
     * return true if option is present
     *
     * @param opt
     */
    public boolean isOptionPresent(String opt) {
        boolean ret = false;
        for (int x = 0; x < 100; x++) {
            if (opt == null ? arguments[x] == null : opt.equals(arguments[x])) {
                ret = true;
            }
        }
        return ret;
    }

    /**
     * list all options - print help
     */
    void ListOptions() {
        //std::cout << "GOT " << option_count << " options..." << std::endl;
        System.out.println("=========================");
        System.out.println("USAGE:");

        for (int i = 0; i < option_count; i++) {
            if (!"".equals(options[i])) {
                String requi;
                if (requireds[i]) {
                    requi = "required";
                } else {
                    requi = "optional";
                }
                System.out.println(options[i] + " : " + descriptions[i] + " (" + requi + ")");
            }
        }
    }

    /**
     * get value of switch/option
     *
     * @param opt
     * @return
     */
    public String GetValue(String opt) {
        String val = "";
        //std::cout << "looking for " << opt << std::endl;
        //found option in field, get value
        for (int i = 0; i < option_count; i++) {
            if (options[i] == null ? opt == null : options[i].equals(opt)) {
                val = values[i];

            }
        }
        return val;
    }

    /**
     * process command line parameters
     *
     * @param argv arguments from main function
     */
    public boolean ProcessOptions(String[] args) {

        //list commandline arguments 
        //System.out.println("command line options: ");
        for (int i = 0; i < args.length; i++) {
            arguments[i] = args[i];
            //System.out.println(arguments[i]);
            for (int f = 0; f < 100; f++) {
                if (options[f] == null ? arguments[i] == null : options[f].equals(arguments[i])) {
                    //match!
                    selecteds[f] = true; //tick as selected on CLI
                }
            }
        }

        //check for required but not found
        for (int x = 0; x < 100; x++) {
            if (requireds[x] && !selecteds[x]) {
                System.out.println("missing required " + options[x] + " parameter!");
                foundmissingwrong = true;
            }
        }

        //check for wrong/non-existing options -------------
        for (int z = 0; z < args.length; z++) {
            if (arguments[z].startsWith(opt_switch)) {
                //FOUND SWITCH, check if required and found
                boolean found = false;
                for (int gg = 0; gg < 100; gg++) {
                    if (arguments[z] == null ? options[gg] == null : arguments[z].equals(options[gg])) {
                        found = true;

                        if (!option_onlys[gg]) {
                            //find value
                            if ((z + 1) < args.length) {
                                if (!arguments[z + 1].startsWith(opt_switch)) {
                                    values[gg] = arguments[z + 1];
                                }
                            }
                        }
                    }
                }
                if (!found) {
                    System.out.println(" option " + arguments[z] + " doesn't exist");
                    foundmissingwrong = true;
                }
            }
            
            

        }

        //if -h found, print help --------------------------
        if (isOptionPresent("-h")) {
            ListOptions();
        }

    return foundmissingwrong;
    }
};
